package com.zbest.zpay.acctrans.share.impl;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.zbest.zpay.acctrans.common.exception.AccTransRuntimeException;
import com.zbest.zpay.acctrans.common.model.DBTransactionServiceResult;
import com.zbest.zpay.acctrans.component.InnerAccountDepositComponent;
import com.zbest.zpay.acctrans.component.InnerAccountWithdrawComponent;
import com.zbest.zpay.acctrans.component.MainAccountDepositComponent;
import com.zbest.zpay.acctrans.component.MainAccountHoldComponent;
import com.zbest.zpay.acctrans.component.MainAccountUnHoldComponent;
import com.zbest.zpay.acctrans.component.MainAccountWithdrawComponent;
import com.zbest.zpay.acctrans.component.OpenMainAccountComponent;
import com.zbest.zpay.acctrans.component.QueryInnerAccountComponent;
import com.zbest.zpay.acctrans.dal.model.AccountInf;
import com.zbest.zpay.acctrans.dal.model.InnerInf;
import com.zbest.zpay.acctrans.dal.model.TransJnl;
import com.zbest.zpay.acctrans.enums.ActAttrFlag;
import com.zbest.zpay.acctrans.enums.HoldFlag;
import com.zbest.zpay.acctrans.enums.TxSts;
import com.zbest.zpay.acctrans.enums.biz.AcctransBizCode;
import com.zbest.zpay.acctrans.share.MasterAccountService;
import com.zbest.zpay.acctrans.share.TransJnlService;

/**
 * Created by wenfeihu on 16/5/26.
 */
@Service("masterAccountService")
public class MasterAccountServiceImpl implements MasterAccountService {
    private static final Logger logger = LoggerFactory
            .getLogger(MasterAccountServiceImpl.class);

    @Autowired
    private TransJnlService transJnlService;

    @Autowired
    private OpenMainAccountComponent openMainAccountComponent;

    @Autowired
    private QueryInnerAccountComponent queryInnerAccountComponent;

    @Autowired
    private InnerAccountDepositComponent innerAccountDepositComponent;

    @Autowired
    private InnerAccountWithdrawComponent innerAccountWithdrawComponent;

    @Autowired
    private MainAccountDepositComponent mainAccountDepositComponent;

    @Autowired
    private MainAccountHoldComponent mainAccountHoldComponent;

    @Autowired
    private MainAccountUnHoldComponent mainAccountUnHoldComponent;

    @Autowired
    private MainAccountWithdrawComponent mainAccountWithdrawComponent;

    /**
     * 事务模板
     */
    @Autowired
    @Qualifier("acctransTransactionTemplate")
    private TransactionTemplate transactionTemplate;

    @Override
    public void handler(TransJnl transJnl, String holdFlag) {
        logger.info("对象tranjnl的数据:" + transJnl.toString());
        /** 主账户开户 */
        openMainAccountComponent.execute(transJnl);
        /** 内部账户的检查 */
        InnerInf drInnerInf = queryInnerAccountComponent.queryDrInner(transJnl);
        InnerInf crInnerInf = queryInnerAccountComponent.queryCrInner(transJnl);
        AccountInf crAccountInf = openMainAccountComponent.queryAccountInf(transJnl.getCrActNo());

        transJnlService.register(transJnl);
        if (StringUtils.equals(holdFlag, HoldFlag.UNHOLD.getCode())) {
            AccountInf drAccountInf = openMainAccountComponent.queryAccountInf(transJnl.getDrActNo());
            unHold(transJnl, drAccountInf);
            transJnl.setJrnSeq((Integer.valueOf(transJnl.getJrnSeq()) + 1) + "");
        }
        debit(transJnl, drInnerInf);
        transJnl.setJrnSeq((Integer.valueOf(transJnl.getJrnSeq()) + 1) + "");
        credit(transJnl, crInnerInf, crAccountInf);
        transJnl.setJrnSeq((Integer.valueOf(transJnl.getJrnSeq()) + 1) + "");
        if (StringUtils.equals(holdFlag, HoldFlag.HOLD.getCode())) {
            hold(transJnl, crAccountInf);
        }
        transJnlService.updateState(TxSts.TX_STS_S.getCode(), transJnl.getJrnNo());
    }

    @Override
    public void holdHandler(TransJnl transJnl, String actTyp) {
        logger.info("对象tranjnl的数据:" + transJnl.toString());
        transJnlService.register(transJnl);
        String actNo = actTyp + transJnl.getHldUsrId();
        AccountInf accountInf = openMainAccountComponent.queryAccountInf(actNo);
        hold(transJnl, accountInf);
        transJnlService.updateState(TxSts.TX_STS_S.getCode(), transJnl.getJrnNo());
    }

    @Override
    public void unHoldHandler(TransJnl transJnl, String actTyp) {
        logger.info("对象tranjnl的数据:" + transJnl.toString());
        transJnlService.register(transJnl);
        String actNo = actTyp + transJnl.getHldUsrId();
        AccountInf accountInf = openMainAccountComponent.queryAccountInf(actNo);
        unHold(transJnl, accountInf);
        transJnlService.updateState(TxSts.TX_STS_S.getCode(), transJnl.getJrnNo());
    }

    /**
     * 借记处理
     *
     * @param transJnl
     */
    public void debit(final TransJnl transJnl, final InnerInf drInnerInf) {
        try {
            logger.info("借记处理开始;");
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {
                    try {
                        String actAttr = transJnl.getDrActAttr();
                        if (StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_PER.getCode())
                                || StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_MER.getCode())) {
                            mainAccountWithdrawComponent.execute(transJnl);
                        } else if (StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_INN.getCode())) {
                            innerAccountWithdrawComponent.execute(transJnl, drInnerInf);
                        } else {
                            throw new AccTransRuntimeException(
                                    AcctransBizCode.ACT_FIELD_NOT_NULL, "ACT_ATTR define error");
                        }
                        logger.info("借记处理成功;");
                        return new DBTransactionServiceResult(true, AcctransBizCode.SUCCESS);
                    } catch (AccTransRuntimeException e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(e.getBizCode(), e);
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
                    }
                }
            });
        } catch (AccTransRuntimeException e) {
            logger.error("", e);
            throw new AccTransRuntimeException(e.getBizCode(), e);
        } catch (Exception e) {
            logger.error("", e);
            throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
        }
        logger.info("借记处理结束;");
    }

    /**
     * 贷记处理
     *
     * @param transJnl
     */
    public void credit(final TransJnl transJnl, final InnerInf crInnerInf, final AccountInf crAccountInf) {
        try {
            logger.info("贷记处理开始;");
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {
                    try {
                        String actAttr = transJnl.getCrActAttr();
                        if (StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_PER.getCode())
                                || StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_MER.getCode())) {
                            mainAccountDepositComponent.execute(transJnl, crAccountInf);
                        } else if (StringUtils.equals(actAttr,
                                ActAttrFlag.ACCOUNT_ATTR_INN.getCode())) {
                            innerAccountDepositComponent.execute(transJnl, crInnerInf);
                        } else {
                            throw new AccTransRuntimeException(
                                    AcctransBizCode.ACT_FIELD_NOT_NULL, "ACT_ATTR define error");
                        }
                        logger.info("贷记处理成功;");
                        return new DBTransactionServiceResult(true, AcctransBizCode.SUCCESS);
                    } catch (AccTransRuntimeException e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(e.getBizCode(), e);
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
                    }
                }
            });
        } catch (AccTransRuntimeException e) {
            logger.error("", e);
            throw new AccTransRuntimeException(e.getBizCode(), e);
        } catch (Exception e) {
            logger.error("", e);
            throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
        }
        logger.info("贷记处理结束;");
    }

    /**
     * 冻结处理
     *
     * @param transJnl
     */
    public void hold(final TransJnl transJnl, final AccountInf crAccountInf) {
        try {
            logger.info("冻结处理开始;");
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {
                    try {
                        mainAccountHoldComponent.execute(transJnl, crAccountInf);
                        logger.info("冻结处理成功;");
                        return new DBTransactionServiceResult(true, AcctransBizCode.SUCCESS);
                    } catch (AccTransRuntimeException e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(e.getBizCode(), e);
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
                    }
                }
            });
        } catch (AccTransRuntimeException e) {
            logger.error("", e);
            throw new AccTransRuntimeException(e.getBizCode(), e);
        } catch (Exception e) {
            logger.error("", e);
            throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
        }
        logger.info("冻结处理结束;");
    }

    /**
     * 解冻处理
     *
     * @param transJnl
     */
    public void unHold(final TransJnl transJnl, final AccountInf drAccountInf) {
        try {
            logger.info("解冻处理开始;");
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {
                    try {
                        mainAccountUnHoldComponent.execute(transJnl, drAccountInf);
                        logger.info("解冻处理成功;");
                        return new DBTransactionServiceResult(true, AcctransBizCode.SUCCESS);
                    } catch (AccTransRuntimeException e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(e.getBizCode(), e);
                    } catch (Exception e) {
                        status.setRollbackOnly();
                        throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
                    }
                }
            });
        } catch (AccTransRuntimeException e) {
            logger.error("", e);
            throw new AccTransRuntimeException(e.getBizCode(), e);
        } catch (Exception e) {
            logger.error("", e);
            throw new AccTransRuntimeException(AcctransBizCode.SYSTEM_ERROR, e);
        }
        logger.info("解冻处理结束;");
    }
}
